# -*- coding:utf8 -*-
import json
import traceback
import os
import time
import requests
import typing
from lxml import etree
from urllib.parse import urlparse
from urllib.request import urlretrieve
from scrapy import Request
from .sign_chrome import SignChrome
from squirrel_core.commons.utils.tools import calc_str_md5, upload_file
from squirrel_core.frame.spider_makaka import MakakaSpider

file_path = os.environ.get("FILE_PATH", "/")


class signup_sign(MakakaSpider):
    name = "signup_sign"
    url = "https://lps.irunner.mobi/match/apply-search?match_eng=68073c33f310f&app_type=&access_token="
    user_url = "https://lps.irunner.mobi/match/runner-info?match_eng=68073c33f310f&app_type=&access_token="
    cq_cjh_url = "https://www.cqnbmarathon.com/mlsreg/cjh/cx.aspx"
    cq_url = "https://www.cqmarathon.com/mlsreg/cqmls/cx.aspx"
    ms_url = "https://www.sichuanbojiesports.com/query/runner/post"
    headers = {
        "Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryw5lBv8ld8DimAAxW",
    }
    specific_settings = {
        'CONCURRENT_REQUESTS': 100
    }
    return_flag = True
    serialNumber = ""
    home_url = ""
    race_id = ""
    race_name = ""
    user_list = []
    retry_time = 3

    def get_ext_requests_or_urls(self, data=None):
        if data and isinstance(data, str):
            data = json.loads(data)
        if data and isinstance(data, typing.MutableMapping):
            self.home_url = data.get("url", "")
            self.race_id = data.get("race_id", "")
            self.serialNumber = data.get("task_id", "")
            self.race_name = data.get("race_name", "").replace(" ", "")
            self.user_list = sorted(data.get("user_list", []), key=lambda x: int(x['priority_level']), reverse=True)
            if not all([self.home_url, self.race_id, self.race_name, self.user_list]):
                self.logger.info("参数不全，请仔细核对")
                self.upload_procedure({"race_id": self.race_id, "code": 203, "message": "参数不全，请仔细核对"})
                self.close_after_idle = True
                self.force_to_close_spider = True
            else:
                self.upload_procedure({"serialNumber": self.serialNumber, "code": 200, "message": "任务启动成功"})
                if "长嘉汇" in self.race_name:
                    for user in self.user_list:
                        time.sleep(10)
                        serial_number = user.get("serialNumber", "")
                        name = user.get("name", "")
                        user_id = user.get("user_id", "")
                        card_num = user.get("card_num", "")
                        priority = int(user.get("priority_level", 0))
                        yield Request(url=self.cq_cjh_url, callback=self.parse_cq, dont_filter=True,
                                      errback=self.err_parse, priority=priority,
                                      meta={"user_id": user_id, "card_num": card_num, "serial_number": serial_number})
                elif "重庆马拉松" in self.race_name:
                    for user in self.user_list:
                        time.sleep(10)
                        serial_number = user.get("serialNumber", "")
                        name = user.get("name", "")
                        user_id = user.get("user_id", "")
                        card_num = user.get("card_num", "")
                        priority = int(user.get("priority_level", 0))
                        yield Request(url=self.cq_url, callback=self.parse_cq, dont_filter=True,
                                      priority=priority, errback=self.err_parse,
                                      meta={"serial_number": serial_number, "user_id": user_id, "card_num": card_num})
                elif "2025眉山东坡马拉松" in self.race_name:
                    for user in self.user_list:
                        serial_number = user.get("serialNumber", "")
                        name = user.get("name", "")
                        user_id = user.get("user_id", "")
                        card_num = user.get("card_num", "")
                        priority = int(user.get("priority_level", 0))
                        yield Request(url=self.ms_url, callback=self.parse_ms, dont_filter=True,
                                      errback=self.err_parse, priority=priority,
                                      method="POST", body=json.dumps({"id_card": card_num, "race_id": 35}),
                                      headers={'Content-Type': 'application/json'},
                                      meta={"serial_number": serial_number, "user_id": user_id, "card_num": card_num})
                else:
                    for user in self.user_list:
                        serial_number = user.get("serialNumber", "")
                        name = user.get("name", "")
                        user_id = user.get("user_id", "")
                        card_num = user.get("card_num", "")
                        priority = int(user.get("priority_level", 0))
                        body = (
                            "------WebKitFormBoundaryw5lBv8ld8DimAAxW\r\n"
                            'Content-Disposition: form-data; name="id_number"\r\n\r\n'
                            f"{card_num}\r\n"
                            f"------WebKitFormBoundaryw5lBv8ld8DimAAxW\r\n"
                            'Content-Disposition: form-data; name="access_token"\r\n\r\n'
                            "ebfb431354aec75da5f5b95111358133\r\n"
                            "------WebKitFormBoundaryw5lBv8ld8DimAAxW--\r\n"
                        ).encode("utf-8")

                        yield Request(url=self.url, callback=self.parse, dont_filter=True, errback=self.err_parse,
                                      body=body, priority=priority, method="POST", headers=self.headers,
                                      meta={"serial_number": serial_number, "user_id": user_id})

    def parse_cq(self, response):
        card_num = response.meta.get("card_num", "")
        serial_number = response.meta.get("serial_number", "")
        user_id = response.meta.get("user_id", "")
        proxy_url = response.request.meta.get("proxy", "")
        proxy_pre = response.request.meta.get("proxy_pre", "")
        try:
            self.logger.info("开始获取报名信息")
            i = 0
            while i < 1:
                try:
                    html = SignChrome().get_sign(response.url, card_num, proxy_url, proxy_pre)
                    if html:
                        data_dict = {}
                        tree = etree.HTML(html)
                        div_list = tree.xpath("//div[@id='t_signup']/div")
                        for div in div_list:
                            name = "".join(div.xpath("./span[@class='l']//text()")).strip()
                            value = "".join(div.xpath("./span[@class='r']//text()")).strip()
                            if name:
                                data_dict[name] = value
                        data_dict.pop("联系电话", "")
                        data_dict.pop("袜子尺码", "")
                        data_dict["name"] = data_dict.pop("选手姓名", "")
                        data_dict["race_item"] = data_dict.pop("参赛项目", "")
                        data_dict["gender"] = data_dict.pop("选手性别", "")
                        data_dict["size"] = data_dict.pop("衣服尺码", "")
                        data_dict["sign_status"] = data_dict.pop("状态", "")
                        result = self.send_data(resp=response, serial_number=serial_number, result_data=data_dict,
                                                user_id=user_id)
                        yield result
                    else:
                        i += 1
                        proxy_url = self.get_proxy() if self.use_proxy else ""
                except Exception:
                    i += 1
                    proxy_url = self.get_proxy() if self.use_proxy else ""
            else:
                result = self.send_data(resp=response, serial_number=serial_number, user_id=user_id)
                yield result
        except Exception:
            self.logger.info(f"获取报名信息出错：{traceback.format_exc()}")

    def parse_ms(self, response):
        serial_number = response.meta.get("serial_number", "")
        user_id = response.meta.get("user_id", "")
        try:
            self.logger.info("开始获取报名信息")
            resp = json.loads(response.text)
            if resp.get("code", "ok") != "ok":
                result = self.send_data(resp=response, serial_number=serial_number, user_id=user_id)
                yield result
            else:
                content = resp.get("runner", {})
                name = content.get("name", "")
                r_no = content.get("bib", "")
                gender = content.get("gender", "")
                race_item = content.get("item", {}).get("title", "")
                sign_status = "是" if content.get("status", 1) == 1 else "否"
                area = content.get("area", "")
                size = content.get("t_shirt", "")
                runner_data = {"runner_status": "报名成功", "name": name, "race_no": r_no,
                               "gender": gender, "race_item": race_item, "sign_status": sign_status,
                               "area": area, "size": size}
                pic_url = resp.get("bib_image", "")
                if pic_url:
                    pic_txt = self.download_pic(pic_url, r_no, self.race_id, user_id)
                    runner_data["race_no_pic"] = pic_txt
                else:
                    runner_data["race_no_pic"] = ""
                result = self.send_data(resp=response, serial_number=serial_number, result_data=runner_data,
                                        user_id=user_id)
                yield result
        except Exception:
            self.logger.info(f"获取报名信息出错：{traceback.format_exc()}")

    def parse(self, response, **kwargs):
        serial_number = response.meta.get("serial_number", "")
        user_id = response.meta.get("user_id", "")
        try:
            self.logger.info("开始获取报名信息")
            if self.return_flag:
                self.return_flag = False
            resp = json.loads(response.text)
            if resp.get("status") != 0:
                result = self.send_data(resp=response, serial_number=serial_number, user_id=user_id)
                yield result
            else:
                content = resp.get("entry_info", {})
                name = content.get("name", "")
                r_no = content.get("bib_no")
                runner_status = "已报名" if content.get("runner_status", "") == "registered" else "报名中"
                entry_id = content.get("entry_id", "")
                body = (
                    "------WebKitFormBoundaryw5lBv8ld8DimAAxW\r\n"
                    'Content-Disposition: form-data; name="entry_id"\r\n\r\n'
                    f"{entry_id}\r\n"
                    "------WebKitFormBoundaryw5lBv8ld8DimAAxW\r\n"
                    'Content-Disposition: form-data; name="access_token"\r\n\r\n'
                    "ebfb431354aec75da5f5b95111358133\r\n"
                    "------WebKitFormBoundaryw5lBv8ld8DimAAxW--\r\n"
                ).encode("utf-8")
                runner_data = {"name": name, "race_no": r_no, "runner_status": runner_status}
                yield Request(url=self.user_url, callback=self.parse_runner, dont_filter=True, errback=self.err_parse,
                              body=body, method="POST", headers=self.headers,
                              meta={"runner_data": runner_data, "user_id": user_id, "serial_number": serial_number})
        except Exception:
            self.logger.info(f"获取报名信息出错：{traceback.format_exc()}")

    def parse_runner(self, response):
        serial_number = response.meta.get("serial_number", "")
        user_id = response.meta.get("user_id", "")
        self.logger.info("开始获取号码牌信息")
        try:
            runner_data = response.meta.get("runner_data", {})
            content = json.loads(response.text)
            race_name = content.get("course", {}).get("course_name", "")
            enroll_status = content.get("runner_info", {}).get("enroll_status_name", "")
            pic_url = content.get("runner_info", {}).get("digital_bib", "")
            runner_data["race_name"] = race_name
            runner_data["enroll_status"] = enroll_status
            if pic_url:
                pic_txt = self.download_pic(pic_url, runner_data["race_no"], self.race_id, user_id)
                runner_data["race_no_pic"] = pic_txt
            else:
                runner_data["race_no_pic"] = ""

            result = self.send_data(resp=response, serial_number=serial_number, result_data=runner_data,
                                    user_id=user_id)
            yield result
        except Exception:
            self.logger.info(f"获取号码牌信息时出错：{traceback.format_exc()}")

    def download_pic(self, pic_url, match_id, race_id, user_id):
        try:
            self.logger.info(f"开始下载图片：{pic_url}")
            path = urlparse(pic_url).path
            suffix = os.path.splitext(path)[1].lower()
            pic_md5 = calc_str_md5(pic_url)
            pic_name = f"{match_id}_{pic_md5}{suffix}"
            dir_path = os.path.join(file_path, self.name_first)
            if not os.path.exists(dir_path):
                os.makedirs(dir_path)
            save_path = os.path.join(dir_path, pic_name)
            if not os.path.exists(save_path):
                urlretrieve(pic_url, save_path)
                upload_path = f"flow/{race_id}/{user_id}/sign/{pic_name}"
                upload_flag = upload_file(save_path, upload_path)
                if upload_flag:
                    self.logger.info(f"{save_path}上传成功：{upload_path}")
                else:
                    self.logger.info(f"{save_path}上传失败：{upload_path}")
                return upload_path
        except Exception:
            self.logger.error(f"下载{pic_url}失败：{traceback.format_exc()}")
            return ""

    def err_parse(self, failure):
        self.logger.warning(f"请求失败：{failure.request.url},错误原因:{traceback.format_exc()}")

    def get_proxy(self):
        url = "http://api.dmdaili.com/dmgetip.asp?apikey=062c68ee&pwd=2ceacf762585db3e1d24cbdb4ef11091&getnum=1&httptype=1&geshi=2&fenge=&fengefu=&operate=all"
        content = requests.get(url).text
        ip = json.loads(content).get("data", [])[0].get("ip", "")
        port = json.loads(content).get("data", [])[0].get("port", "")
        proxy = f"http://{ip}:{port}"
        return proxy

    def send_data(self, resp=None, serial_number=None, result_data=None, user_id=None):
        if result_data is None:
            result_data = {"msg": "未查到报名信息"}
        result_dict = {"serialNumber": serial_number, "webType": self.name_first,
                       "userId": user_id, "raceId": self.race_id, "code": 200,
                       "crawlerType": self.name_second, "data": str(result_data)}
        result = self.result_item_assembler(resp)
        result['result_data'] = result_dict
        return result
